package com.witmore.neutron.ai.web.wechat.service.impl;

import com.alibaba.fastjson2.JSON;
import com.jk.mp.wx.client.WeChatClient;
import com.jk.mp.wx.config.WechatServiceProperties;
import com.jk.mp.wx.constant.WeChatUtils;
import com.jk.mp.wx.request.WeChatAccessTokenRequest;
import com.jk.mp.wx.response.AccessTokenResponse;
import com.witmore.neutron.ai.web.wechat.dto.CreateQrCodeRequest;
import com.witmore.neutron.ai.web.wechat.dto.CreateQrCodeResponse;
import com.witmore.neutron.ai.web.wechat.dto.CustomMenuDTO;
import com.witmore.neutron.ai.web.wechat.dto.CustomMenuResponse;
import com.witmore.neutron.ai.web.wechat.service.WechatService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.util.concurrent.TimeUnit;
import java.util.function.Function;

import static com.jk.mp.wx.constant.WeChatUtils.BUS_WECHAT_GET_STABLE_TOKEN;

/**
 * 微信服务实现类
 * Author: 豆子高
 * Date: 2025/12/19
 */
@Slf4j
@Service
public class WechatServiceImpl implements WechatService {

    @Autowired
    private WechatServiceProperties wechatProperties;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    private final RestTemplate restTemplate = new RestTemplate();

    private static final String ACCESS_TOKEN_CACHE_KEY = "wechat:access_token";

    @Autowired
    private WeChatClient weChatClient;

    /**
     * 通用的微信API调用重试机制
     *
     * @param apiCaller       API调用函数，参数为access_token
     * @param responseChecker 响应检查函数，用于判断是否为token失效错误
     * @param operationName   操作名称，用于日志记录
     * @param <T>             返回类型
     * @return API调用结果
     */
    private <T> T executeWechatApiWithRetry(Function<String, T> apiCaller,
                                            Function<T, Boolean> responseChecker,
                                            String operationName) {
        return executeWechatApiWithRetry(apiCaller, responseChecker, operationName, false);
    }

    /**
     * 通用的微信API调用重试机制（内部实现）
     *
     * @param apiCaller       API调用函数，参数为access_token
     * @param responseChecker 响应检查函数，用于判断是否为token失效错误
     * @param operationName   操作名称，用于日志记录
     * @param isRetry         是否为重试调用
     * @param <T>             返回类型
     * @return API调用结果
     */
    private <T> T executeWechatApiWithRetry(Function<String, T> apiCaller,
                                            Function<T, Boolean> responseChecker,
                                            String operationName,
                                            boolean isRetry) {
        String accessToken = getAccessToken();
        if (!StringUtils.hasText(accessToken)) {
            log.error("获取AccessToken失败，无法执行{}操作", operationName);
            return null;
        }

        try {
            T result = apiCaller.apply(accessToken);

            // 检查是否为token失效错误
            if (result != null && responseChecker.apply(result) && !isRetry) {
                log.warn("{}操作检测到access_token失效，尝试刷新token并重试", operationName);
                // 强制刷新token
                String newToken = refreshAccessToken();
                if (StringUtils.hasText(newToken)) {
                    log.info("access_token刷新成功，开始重试{}操作", operationName);
                    return executeWechatApiWithRetry(apiCaller, responseChecker, operationName, true);
                }
            }

            return result;
        } catch (Exception e) {
            log.error("执行{}操作异常", operationName, e);
            return null;
        }
    }


    @Override
    public String getAccessToken() {
        // 先从Redis缓存中获取
        String cachedToken = redisTemplate.opsForValue().get(ACCESS_TOKEN_CACHE_KEY);
        if (StringUtils.hasText(cachedToken)) {
            return cachedToken;
        }

        // 缓存中没有，重新获取
        return refreshAccessToken();
    }

    @Override
    public String refreshAccessToken() {
        try {
            log.info("开始刷新微信AccessToken");

            // 先清除缓存中的token
            redisTemplate.delete(ACCESS_TOKEN_CACHE_KEY);

            // 调用微信API获取新的AccessToken
            WeChatAccessTokenRequest request = new WeChatAccessTokenRequest();
            request.setAppid(wechatProperties.getAppId());
            request.setSecret(wechatProperties.getAppSecret());
            AccessTokenResponse tokenResponse = weChatClient.executorPostHandler(request, AccessTokenResponse.class, BUS_WECHAT_GET_STABLE_TOKEN);

            if (tokenResponse != null && StringUtils.hasText(tokenResponse.getAccess_token())) {
                // 缓存AccessToken，提前5分钟过期以避免边界问题
                int expireTime = tokenResponse.getExpires_in() - 300;
                redisTemplate.opsForValue().set(ACCESS_TOKEN_CACHE_KEY, tokenResponse.getAccess_token(),
                        expireTime, TimeUnit.SECONDS);

                log.info("刷新微信AccessToken成功，新token已缓存，过期时间：{}秒", expireTime);
                return tokenResponse.getAccess_token();
            } else {
                log.error("刷新微信AccessToken失败");
            }
        } catch (Exception e) {
            log.error("刷新微信AccessToken异常", e);
        }
        return null;
    }

    @Override
    public CreateQrCodeResponse createQrCode(String sceneStr, Integer expireSeconds) {
        return executeWechatApiWithRetry(
                // API调用函数
                accessToken -> callCreateQrCodeApi(accessToken, sceneStr, expireSeconds),
                // 响应检查函数，判断是否为token失效错误
                response -> response != null && response.getErrcode() != null && response.getErrcode() == 40001,
                // 操作名称
                "创建二维码"
        );
    }

    /**
     * 调用创建二维码API
     *
     * @param accessToken   访问令牌
     * @param sceneStr      场景值
     * @param expireSeconds 过期时间
     * @return 二维码响应
     */
    private CreateQrCodeResponse callCreateQrCodeApi(String accessToken, String sceneStr, Integer expireSeconds) {
        try {
            CreateQrCodeRequest request = new CreateQrCodeRequest();
            request.setExpireSeconds(expireSeconds != null ? expireSeconds : 1800); // 默认30分钟
            request.setActionName("QR_STR_SCENE");

            CreateQrCodeRequest.ActionInfo actionInfo = new CreateQrCodeRequest.ActionInfo();
            CreateQrCodeRequest.Scene scene = new CreateQrCodeRequest.Scene();
            scene.setSceneStr(sceneStr);
            actionInfo.setScene(scene);
            request.setActionInfo(actionInfo);

            String url = String.format(WeChatUtils.CREATE_QRCODE_URL, accessToken);
            CreateQrCodeResponse createQrCodeResponse = weChatClient.executorPostHandler(request, CreateQrCodeResponse.class, url);
            if (createQrCodeResponse == null) {
                log.error("创建二维码失败: {}", "null");
                return null;
            }
            return createQrCodeResponse;
        } catch (Exception e) {
            log.error("调用创建二维码API异常，场景值：{}", sceneStr, e);
        }
        return null;
    }

    @Override
    public String getQrCodeImageUrl(String ticket) {
        return String.format(WeChatUtils.SHOW_QRCODE_URL, ticket);
    }

    @Override
    public CustomMenuResponse createCustomMenu(CustomMenuDTO menuDTO) {
        return executeWechatApiWithRetry(
                // API调用函数
                accessToken -> callCreateMenuApi(accessToken, menuDTO),
                // 响应检查函数，判断是否为token失效错误
                response -> response != null && response.getErrcode() != null && response.getErrcode() == 40001,
                // 操作名称
                "创建自定义菜单"
        );
    }

    @Override
    public CustomMenuResponse deleteCustomMenu() {
        return executeWechatApiWithRetry(
                // API调用函数
                this::callDeleteMenuApi,
                // 响应检查函数，判断是否为token失效错误
                response -> response != null && response.getErrcode() != null && response.getErrcode() == 40001,
                // 操作名称
                "删除自定义菜单"
        );
    }

    @Override
    public CustomMenuDTO getCustomMenu() {
        return executeWechatApiWithRetry(
                // API调用函数
                this::callGetMenuApi,
                // 响应检查函数，判断是否为token失效错误
                response -> response == null,
                // 操作名称
                "获取自定义菜单"
        );
    }

    @Override
    public CustomMenuResponse createDefaultCustomMenu() {
        // 构建默认菜单
        CustomMenuDTO menuDTO = buildDefaultMenuPro();
        return createCustomMenu(menuDTO);
    }

    /**
     * 构建默认的自定义菜单
     *
     * @return 默认菜单配置
     */
    private CustomMenuDTO buildDefaultMenuPro() {
        CustomMenuDTO menuDTO = new CustomMenuDTO();

        // 创建AI服务主菜单
        CustomMenuDTO.MenuButton aiServiceButton = new CustomMenuDTO.MenuButton();
        aiServiceButton.setName("AI服务");
        aiServiceButton.setType("view");

        // 创建AI服务子菜单
        CustomMenuDTO.MenuButton stockAlertButton = new CustomMenuDTO.MenuButton();
        stockAlertButton.setName("股票异动助手");
        stockAlertButton.setType("view");
        stockAlertButton.setUrl("https://ai-pro.witmore.cn/chat/r6FisgH5ve7ylkCA");

        CustomMenuDTO.MenuButton configToolButton = new CustomMenuDTO.MenuButton();
        configToolButton.setName("异动配置工具");
        configToolButton.setType("view");
        configToolButton.setUrl("https://ai.witmore.cn/h5x/neutron/stock/config");

        CustomMenuDTO.MenuButton abnormalRecordButton = new CustomMenuDTO.MenuButton();
        abnormalRecordButton.setName("异动记录");
        abnormalRecordButton.setType("view");
        abnormalRecordButton.setUrl("https://ai.witmore.cn/h5x/neutron/stock/abnormal");

        // 设置AI服务子菜单
        aiServiceButton.setSubButton(java.util.Arrays.asList(stockAlertButton, configToolButton, abnormalRecordButton));

        // 创建关于我们菜单
        CustomMenuDTO.MenuButton aboutButton = new CustomMenuDTO.MenuButton();
        aboutButton.setName("关于我们");
        aboutButton.setType("view");
        aboutButton.setUrl("https://ai.witmore.cn/wechat/h5/about");

        // 创建文档菜单
        CustomMenuDTO.MenuButton docButton = new CustomMenuDTO.MenuButton();
        docButton.setName("文档");
        docButton.setType("view");
        docButton.setUrl("https://developers.weixin.qq.com/doc/service/guide/product/menu/intro.html");

        // 设置一级菜单
        menuDTO.setButton(java.util.Arrays.asList(aiServiceButton, aboutButton, docButton));

        return menuDTO;
    }

    /**
     * 构建默认的自定义菜单
     *
     * @return 默认菜单配置
     */
    private CustomMenuDTO buildDefaultMenu() {
        CustomMenuDTO menuDTO = new CustomMenuDTO();

        // 创建AI服务主菜单
        CustomMenuDTO.MenuButton aiServiceButton = new CustomMenuDTO.MenuButton();
        aiServiceButton.setName("AI服务");
        aiServiceButton.setType("view");

        // 创建AI服务子菜单
        CustomMenuDTO.MenuButton stockAlertButton = new CustomMenuDTO.MenuButton();
        stockAlertButton.setName("股票异动助手");
        stockAlertButton.setType("view");
        stockAlertButton.setUrl("https://ai-test.witmore.cn/chat/r6FisgH5ve7ylkCA");

        CustomMenuDTO.MenuButton configToolButton = new CustomMenuDTO.MenuButton();
        configToolButton.setName("异动配置工具");
        configToolButton.setType("view");
        configToolButton.setUrl("https://ai-beta.witmore.cn/h5x/neutron/stock/config");

        CustomMenuDTO.MenuButton abnormalRecordButton = new CustomMenuDTO.MenuButton();
        abnormalRecordButton.setName("异动记录");
        abnormalRecordButton.setType("view");
        abnormalRecordButton.setUrl("https://ai-beta.witmore.cn/h5x/neutron/stock/abnormal");

        // 设置AI服务子菜单
        aiServiceButton.setSubButton(java.util.Arrays.asList(stockAlertButton, configToolButton, abnormalRecordButton));

        // 创建关于我们菜单
        CustomMenuDTO.MenuButton aboutButton = new CustomMenuDTO.MenuButton();
        aboutButton.setName("关于我们");
        aboutButton.setType("view");
        aboutButton.setUrl("https://ai-beta.witmore.cn/wechat/h5/about");

        // 创建文档菜单
        CustomMenuDTO.MenuButton docButton = new CustomMenuDTO.MenuButton();
        docButton.setName("文档");
        docButton.setType("view");
        docButton.setUrl("https://developers.weixin.qq.com/doc/service/guide/product/menu/intro.html");

        // 设置一级菜单
        menuDTO.setButton(java.util.Arrays.asList(aiServiceButton, aboutButton, docButton));

        return menuDTO;
    }

    /**
     * 调用创建自定义菜单API
     *
     * @param accessToken 访问令牌
     * @param menuDTO     菜单配置
     * @return 创建结果
     */
    private CustomMenuResponse callCreateMenuApi(String accessToken, CustomMenuDTO menuDTO) {
        try {
            String url = WeChatUtils.CREATE_MENU_URL.replace("ACCESS_TOKEN", accessToken);
            HttpHeaders headers = new HttpHeaders();
            headers.add("Content-Type", "application/json");

            String jsonBody = JSON.toJSONString(menuDTO);
            log.info("创建自定义菜单请求体: {}", jsonBody);

            HttpEntity<String> httpEntity = new HttpEntity<>(jsonBody, headers);
            ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class);

            if (response.getStatusCode().is2xxSuccessful() && StringUtils.hasText(response.getBody())) {
                CustomMenuResponse menuResponse = JSON.parseObject(response.getBody(), CustomMenuResponse.class);

                if (menuResponse.getErrcode() == null || menuResponse.getErrcode() == 0) {
                    log.info("创建自定义菜单成功");
                } else {
                    log.error("创建自定义菜单失败: errcode={}, errmsg={}",
                            menuResponse.getErrcode(), menuResponse.getErrmsg());
                }

                return menuResponse;
            } else {
                log.error("创建自定义菜单请求失败: statusCode={}, body={}",
                        response.getStatusCode(), response.getBody());
            }
        } catch (Exception e) {
            log.error("调用创建自定义菜单API异常", e);
        }

        return null;
    }

    /**
     * 调用删除自定义菜单API
     *
     * @param accessToken 访问令牌
     * @return 删除结果
     */
    private CustomMenuResponse callDeleteMenuApi(String accessToken) {
        try {
            String url = WeChatUtils.DELETE_MENU_URL.replace("ACCESS_TOKEN", accessToken);
            ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);

            if (response.getStatusCode().is2xxSuccessful() && StringUtils.hasText(response.getBody())) {
                CustomMenuResponse menuResponse = JSON.parseObject(response.getBody(), CustomMenuResponse.class);

                if (menuResponse.getErrcode() == null || menuResponse.getErrcode() == 0) {
                    log.info("删除自定义菜单成功");
                } else {
                    log.error("删除自定义菜单失败: errcode={}, errmsg={}",
                            menuResponse.getErrcode(), menuResponse.getErrmsg());
                }

                return menuResponse;
            } else {
                log.error("删除自定义菜单请求失败: statusCode={}, body={}",
                        response.getStatusCode(), response.getBody());
            }
        } catch (Exception e) {
            log.error("调用删除自定义菜单API异常", e);
        }

        return null;
    }

    /**
     * 调用获取自定义菜单API
     *
     * @param accessToken 访问令牌
     * @return 菜单配置
     */
    private CustomMenuDTO callGetMenuApi(String accessToken) {
        try {
            String url = WeChatUtils.GET_MENU_URL.replace("ACCESS_TOKEN", accessToken);
            ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);

            if (response.getStatusCode().is2xxSuccessful() && StringUtils.hasText(response.getBody())) {
                // 解析响应，微信API返回的格式是 {"menu": {...}}
                String responseBody = response.getBody();
                log.info("获取自定义菜单响应: {}", responseBody);

                // 如果包含错误码，说明是错误响应
                if (responseBody.contains("errcode")) {
                    CustomMenuResponse errorResponse = JSON.parseObject(responseBody, CustomMenuResponse.class);
                    log.error("获取自定义菜单失败: errcode={}, errmsg={}",
                            errorResponse.getErrcode(), errorResponse.getErrmsg());
                    return null;
                }

                // 解析菜单数据
                com.alibaba.fastjson2.JSONObject jsonObject = JSON.parseObject(responseBody);
                if (jsonObject.containsKey("menu")) {
                    CustomMenuDTO menuDTO = JSON.parseObject(jsonObject.getString("menu"), CustomMenuDTO.class);
                    log.info("获取自定义菜单成功");
                    return menuDTO;
                }
            } else {
                log.error("获取自定义菜单请求失败: statusCode={}, body={}",
                        response.getStatusCode(), response.getBody());
            }
        } catch (Exception e) {
            log.error("调用获取自定义菜单API异常", e);
        }

        return null;
    }
}
